package org.vacoor.nothing.misc.express.fedex;

import com.fedex.locations.stub.*;
import org.apache.axis.types.NonNegativeInteger;

import java.math.BigDecimal;
import java.util.Calendar;

/**
 * 根据国家+邮编查找附近位置
 * <p/>
 * 原来的 AddressValidation 过时了, 换成了 LocationSearch
 *
 * @author vacoor
 */
public class FedExLocsSearchService extends FedExSupport {

    /**
     * 根据国家和邮编查找地址, 允许提供更加精确地信息, 但是如果这些信息不正确将被忽略(以国家+邮编为准)
     *
     * @param nearToAddress
     */
    public void search(Address nearToAddress) {
        SearchLocationsRequest req = new SearchLocationsRequest();

        // 授权, 客户端, 协议版本信息
        req.setWebAuthenticationDetail(new WebAuthenticationDetail(new WebAuthenticationCredential(getKey(), getPassword())));
        req.setClientDetail(new ClientDetail(getAccountNumber(), getMeterNumber(), getIntegratorId(), null, null, null));
        req.setTransactionDetail(new TransactionDetail("Locations Search Request", null));
        req.setVersion(new VersionId("locs", 1, 0, 0));

        // 请求信息
        // req.setPhoneNumber("1234567890");
        /*
        Address nearToAddress = new Address();
        nearToAddress.setCountryCode("US");          // 必须
        nearToAddress.setPostalCode("38017");       // 必须
        // nearToAddress.setStateOrProvinceCode("TN");
        // nearToAddress.setCity("Collierville");
        // nearToAddress.setStreetLines(new String[]{"10 FedEx Pkwy"});
        */

        req.setAddress(nearToAddress);

        // 有效日期
        req.setEffectiveDate(Calendar.getInstance().getTime());
        req.setLocationsSearchCriterion(LocationsSearchCriteriaType.ADDRESS);
        req.setMultipleMatchesAction(MultipleMatchesActionType.RETURN_ALL);

        LocationSortDetail locationSortDetail = new LocationSortDetail();
        locationSortDetail.setCriterion(LocationSortCriteriaType.DISTANCE);
        locationSortDetail.setOrder(LocationSortOrderType.LOWEST_TO_HIGHEST);
        req.setSortDetail(locationSortDetail);

        // 搜索约束
        SearchLocationConstraints searchConstraints = new SearchLocationConstraints();

        // 半径距离
        Distance radiusDistance = new Distance();
        radiusDistance.setUnits(DistanceUnits.MI);  // MI - 英里, KM - 千米
        radiusDistance.setValue(new BigDecimal(10));
        searchConstraints.setRadiusDistance(radiusDistance);

        // 排除位置以外的州/省
        searchConstraints.setResultsFilters(new LocationSearchFilterType[]{LocationSearchFilterType.EXCLUDE_LOCATIONS_OUTSIDE_STATE_OR_PROVINCE});
        searchConstraints.setSupportedRedirectToHoldServices(new SupportedRedirectToHoldServiceType[]{SupportedRedirectToHoldServiceType.FEDEX_EXPRESS});
        searchConstraints.setRequiredLocationAttributes(new LocationAttributesType[]{LocationAttributesType.ACCEPTS_CASH});
        searchConstraints.setResultsToSkip(new NonNegativeInteger("1"));
        searchConstraints.setLocationContentOptions(new LocationContentOptionType[]{LocationContentOptionType.HOLIDAYS});
        searchConstraints.setLocationTypesToInclude(new FedExLocationType[]{FedExLocationType.FEDEX_OFFICE});

        req.setConstraints(searchConstraints);
        //
        try {
            // Initialize the service
            LocationsServiceLocator service;
            LocationsPortType port;
            //
            service = new LocationsServiceLocator();
            // updateEndPoint(service);
            port = service.getLocationsServicePort();
            // This is the call to the web service passing in decode SearchLocationsRequest and returning decode SearchLocationsReply
            SearchLocationsReply reply = port.searchLocations(req);

            // 请求成功
            if (isResponseOk(reply.getHighestSeverity())) {
                // NonNegativeInteger resultsReturned = reply.getResultsReturned();
                // NonNegativeInteger totalResultsAvailable = reply.getTotalResultsAvailable();

                // 相关地址
                AddressToLocationRelationshipDetail[] relDetails = reply.getAddressToLocationRelationships();

                for (int i = 0; i < relDetails.length; i++) {
                    AddressToLocationRelationshipDetail relDetail = relDetails[i];
                    // atlrd.getDistanceAndLocationDetails();  // 获取关联地址距离和位置
                    Address matched = relDetail.getMatchedAddress();    //

                    System.out.println("Matched Address");
                    String streetLine[] = matched.getStreetLines();
                    if (streetLine != null) {
                        for (int j = 0; j < streetLine.length; j++) {
                            printString("", streetLine[j], " ");
                        }
                    }
                    printString(matched.getCity(), "City", " ");
                    printString(matched.getStateOrProvinceCode(), "State/Province", " ");
                    printString(matched.getPostalCode(), "Postal Code", " ");
                    printString(matched.getCountryCode(), "Country", " ");
                }
            }

            printNotifications(reply.getNotifications());

        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    private static void printString(String value, String description, String space) {
        if (value != null) {
            System.out.println(space + description + ": " + value);
        }
    }

    private static void printNotifications(Notification[] notifications) {
        System.out.println("*************************************************************");
        System.out.println("Notifications:");
        if (notifications == null || notifications.length == 0) {
            System.out.println("  No notifications returned");
        }
        for (int i = 0; i < notifications.length; i++) {
            Notification n = notifications[i];
            System.out.print("  Notification no. " + i + ": ");
            if (n == null) {
                System.out.println("null");
                continue;
            } else {
                System.out.println("");
            }
            NotificationSeverityType nst = n.getSeverity();

            System.out.println("    Severity: " + (nst == null ? "null" : nst.getValue()));
            System.out.println("    Code: " + n.getCode());
            System.out.println("    Message: " + n.getMessage());
            System.out.println("    Source: " + n.getSource());
        }
    }

    /* ***********************
     *      Helper Method
     * ***********************/
    private static boolean isResponseOk(NotificationSeverityType notificationSeverityType) {
        if (notificationSeverityType == null) {
            return false;
        }

        if (notificationSeverityType.equals(NotificationSeverityType.WARNING) ||
                notificationSeverityType.equals(NotificationSeverityType.NOTE) ||
                notificationSeverityType.equals(NotificationSeverityType.SUCCESS)) {
            return true;
        }
        return false;
    }
}
